#include "rpc_client.h"
#include <list>
#include <qdebug>
#include "../common/collection_type.h"
#include "../common/factor_type.h"
#include "../common/contract_type.h"
#include "../common/strategy_type.h"
#include <unordered_map>
RpcClient::RpcClient(std::string adress)
{
	if (adress.length() > 0)
		stub_ = DataExchange::DataQuery::NewStub(grpc::CreateChannel(adress, grpc::InsecureChannelCredentials()));
	cq_ = std::make_shared<CompletionQueue>() ;
}

RpcClient::~RpcClient()
{
	//qDebug() << "destroy rpc client ..";
	//cq_.Shutdown();
	//stub_->
}

void RpcClient::listTarget(int target, std::unique_ptr< Event> event)
{
	DataExchange::ListRequest request;
	request.set_tablename(DataExchange::TableName(target));

	switch (DataExchange::TableName(target))
	{
	case DataExchange::Collections: {
		auto call = new CallData<DataExchange::CollectionsResponse>(DataExchange::TableName(target),std::move(event));
		call->geter = [call]()->std::any {
			auto v = std::list<std::shared_ptr<Collection>>();;
			for (auto i = call->reply.mutable_collection()->begin(); i != call->reply.mutable_collection()->end(); ++i)
			{
				auto c = std::make_shared< Collection>();
				c->id = i->id(); c->code = i->code();
				c->name.assign(*(i->release_name()));
				c->category = i->category();

				v.emplace_back(c);
			}

			return v; };
		call->response_reader = stub_->PrepareAsyncListCollections(&call->context, request, cq_.get());
		call->response_reader->StartCall();
		call->response_reader->Finish(&call->reply, &call->status, (void*)call);
		break;
	}
	case DataExchange::GlobalFactors: {
		auto call = new CallData<DataExchange::FactorsResponse>(DataExchange::TableName(target), std::move(event));
		call->geter = [call]()->std::any {
			auto v = std::map<uint32_t,std::shared_ptr<Factor>>();
			for (auto i = call->reply.mutable_factor()->begin(); i != call->reply.mutable_factor()->end(); ++i)
			{
				auto c = std::make_shared< Factor>();
				c->id = i->id(); c->code = i->code();
				c->name.assign(*(i->release_name()));
				c->category = i->category();
				v[c->id]=std::move(c);
			}
			return v; };
		call->response_reader = stub_->PrepareAsyncListFactors(&call->context, request, cq_.get());
		call->response_reader->StartCall();
		call->response_reader->Finish(&call->reply, &call->status, (void*)call);
		break;
	}
	case DataExchange::GlobalContracts: {
		auto call = new CallData<DataExchange::ContractsResponse>(DataExchange::TableName(target), std::move(event));
		call->geter = [call]()->std::any {
			auto v = std::unordered_map<uint32_t, std::shared_ptr<Contract>>();
			v.reserve(call->reply.contract().size());
			auto d = call->reply.contract();
			for (auto i = call->reply.mutable_contract()->begin(); i != call->reply.mutable_contract()->end(); ++i)
			{
				auto c = std::make_shared< Contract>();
				c->id = i->id();
				c->exchange =(Exchange)(int)(i->exchange());
				c->symbol.assign(*(i->release_symbol()));
				c->unit = i->slotcnt();
				c->name.assign(*(i->release_name()));
				c->precision = i->pointcnt();
	
				v[c->id] = std::move(c);
			}
		
			return v; 
		};
		call->response_reader = stub_->PrepareAsyncListContracts(&call->context, request, cq_.get());
		call->response_reader->StartCall();
		call->response_reader->Finish(&call->reply, &call->status, (void*)call);
		break;
	}
	case DataExchange::Strategies: {
		auto call = new CallData<DataExchange::StrategiesResponse>(DataExchange::TableName(target), std::move(event));
		call->geter = [call]()->std::any {
			auto v = std::list< std::shared_ptr<Strategy>>();
			for (auto i = call->reply.mutable_strategy()->begin(); i != call->reply.mutable_strategy()->end(); ++i)
			{
				auto c = std::make_shared< Strategy>();
				c->id = i->id();
				c->code = i->code();
				c->collection_id = i->collection_id();
				c->name.assign(*(i->release_name()));
				
				v.emplace_back( c);
			}
			return v; };
		call->response_reader = stub_->PrepareAsyncListStrategies(&call->context, request, cq_.get());
		call->response_reader->StartCall();
		call->response_reader->Finish(&call->reply, &call->status, (void*)call);
		break;
	}
	default:
		break;
	}





}

void RpcClient::ItemDetail(int target, uint32_t rowid, std::unique_ptr<Event> event)
{
	DataExchange::ItemRequest request;
	request.set_tablename(DataExchange::TableName(target));
	request.set_rowid(rowid);
	switch (DataExchange::TableName(target)) {
	case DataExchange::Collections: {
		auto call = new CallData<DataExchange::Collection>(DataExchange::TableName(target), std::move(event));
		call->geter = [call]()->std::any {
			auto v = std::make_shared<Collection>();
			v->id = call->reply.id();
			int itemcnt = call->reply.contracts().size() / 8;
			v->contracts_id.reserve(itemcnt);
			auto data = call->reply.mutable_contracts()->data();
			for (int i=0; i < itemcnt; i++) {
				v->contracts_id[i] = *((uint64_t*)data + i * 8);
			}
			itemcnt = call->reply.factor_id_size() / 4;
			v->factors_id.reserve(itemcnt);
			int j = 0;
			for (auto i = call->reply.factor_id().begin(); i != call->reply.factor_id().end(); ++i)
			{
				v->factors_id[j++] = *i;
			}

			return v;
		};

			
		call->response_reader = stub_->PrepareAsyncCollectionDetail(&call->context, request, cq_.get());
		call->response_reader->StartCall();
		call->response_reader->Finish(&call->reply, &call->status, (void*)call);
		break;
	}
	default:
		break;
	}
}

void RpcClient::start()
{
		
	/*if (stub_) {

		listTarget(DataExchange::Collections);
	}
	else {
		throw "addressed should be provided.";
	}*/
	
}

void RpcClient::stop()
{
	//cq_->Shutdown();
	void* tag;
	bool ok;
	while (cq_->Next(&tag, &ok));
	stub_.reset();
}

std::shared_ptr<CompletionQueue> RpcClient::complettionQueue()
{
	return cq_;
}

